package com.jfinal.ssl.controller;

import cn.hutool.core.date.DateUtil;
import com.jfinal.aop.Inject;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.Ret;
import com.tencentcloudapi.ssl.v20191205.models.Certificates;
import com.tencentcloudapi.ssl.v20191205.models.DescribeCertificatesResponse;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

public class SslServer {
    public static String SecretId;
    public static String SecretKey;
    //SSL服务类型: nginx tomcat apache iis jks other root
    public static String ServiceType;
    public static String path;
    public static int NearlyDay;
    public static List<String> DoMainList;
    @Inject
    TencentServer tencentServer;//腾讯api接口请求方法

    public Ret doMain() throws IOException, CertificateException {
        Ret ret = Ret.ok();

        // 获取证书信息[9](@ref)
        DescribeCertificatesResponse certificatesResponse = tencentServer.getSslList();
        Certificates[] certificates = certificatesResponse.getCertificates();
        List<Certificates> certificatesList = Arrays.stream(certificates).toList();

        for (String doMain : DoMainList) {
            // 获取对应域名的证书列表[9](@ref)
            List<Certificates> doMainCertificates = certificatesList.stream()
                    .filter(cert -> cert.getDomain().equals(doMain))
                    .collect(Collectors.toList());

            if (doMainCertificates.isEmpty()) {
                // 重新申请新的证书，ssl列表中没有我关注的证书
                System.out.println("域名 " + doMain + " 在证书列表中不存在，申请新证书");
                tencentServer.getFreeSSL(doMain);
            } else {
                // 获取最新的证书（按到期时间排序）
                Certificates latestCloudCert = doMainCertificates.stream()
                        .filter(cert -> cert.getStatus() == 1) // 只处理已颁发的证书
                        .max(Comparator.comparing(Certificates::getCertEndTime))
                        .orElse(null);

                if (latestCloudCert != null) {
                    // 检查本地证书是否与云上最新证书一致
                    boolean isConsistent = isCertificateConsistent(doMain, latestCloudCert);

                    if (!isConsistent) {
                        System.out.println("证书不一致，下载最新证书: " + doMain);
                        tencentServer.downSSL(latestCloudCert.getCertificateId());
                    }

                    // 检查证书是否快过期
                    if (isKuaiGuoQi(latestCloudCert.getCertEndTime(), doMain)) {
                        System.out.println("证书即将过期，重新申请: " + doMain);
                        tencentServer.getFreeSSL(doMain);
                    }
                }

                // 清理过期或无效证书
                cleanupInvalidCertificates(doMainCertificates);
            }
        }
        return ret;
    }

    /**
     * 清理过期或无效证书
     */
    private void cleanupInvalidCertificates(List<Certificates> certificates) {
        List<Integer> invalidStatuses = Arrays.asList(2, 3, 6, 7, 9, 10);

        for (Certificates cert : certificates) {
            if (invalidStatuses.contains(cert.getStatus())) {
                System.out.println("执行删除证书：" + cert.getDomain());
                tencentServer.deleteSSL(cert.getCertificateId());
            }
        }
    }

    //判断是否快过期
    public boolean isKuaiGuoQi(String certEndTimeStr, String doMain) {
        // 创建格式化器
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
        // 解析证书到期时间
        DateTime certEndTime = formatter.parseDateTime(certEndTimeStr);
        // 获取当前时间
        DateTime now = new DateTime();
        // 计算证书距离7天(默认)的时间点
        int daysLeft = Days.daysBetween(now, certEndTime).getDays();
        System.out.println("daysLeft: " + daysLeft);
        System.out.println("NearlyDay: " + NearlyDay);
        if (daysLeft < NearlyDay) {
            System.out.println("快到期 " + daysLeft + " domain: " + doMain);
            //重新申请新的证书
            return true;
        } else {
            // 计算距离到期还有多少天
            System.out.println(doMain + "证书安全，到期剩余天数: " + daysLeft);
            return false;
        }
    }



    /**
     * 增强版证书比较（包含指纹验证）
     */
    private boolean compareCertificatesEnhanced(X509Certificate localCert, Certificates cloudCert)
            throws Exception {

        // 计算本地证书指纹[2](@ref)
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] localCertEncoded = localCert.getEncoded();
        String localThumbprint = toHexString(md.digest(localCertEncoded));

        System.out.println("本地证书SHA-256指纹: " + localThumbprint);

        // 这里需要从云API获取证书指纹进行比较
        // String cloudThumbprint = getCloudCertThumbprint(cloudCert.getCertificateId());

        // 基础信息比较
        boolean basicInfoMatch = compareCertificates(localCert, cloudCert);

        // 可以添加更多比较逻辑，如主题备用名称(SAN)等
        return basicInfoMatch; // && localThumbprint.equals(cloudThumbprint);
    }

    /**
     * 字节数组转十六进制字符串
     */
    private static String toHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }


    /**
     * 判断硬盘中的证书是否与腾讯云SSL证书列表的最新证书一致
     * @param doMain 域名
     * @param latestCloudCert 腾讯云上最新的证书信息
     * @return true表示一致，false表示不一致
     */
    private boolean isCertificateConsistent(String doMain, Certificates latestCloudCert)
            throws IOException, CertificateException {

        File sslDir = new File(path);

        // 检查目录是否存在
        if (!sslDir.exists() || !sslDir.isDirectory()) {
            System.out.println("证书目录不存在: " + path);
            return false;
        }

        // 查找域名对应的证书文件
        File certFile = findDomainCertificateFile(sslDir, doMain);
        if (certFile == null) {
            System.out.println("未找到域名为前缀的证书文件: " + doMain);
            return false;
        }

        try (FileInputStream fis = new FileInputStream(certFile)) {
            // 解析本地证书[5,7](@ref)
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate localCert = (X509Certificate) cf.generateCertificate(fis);

            // 比较证书关键信息[1,6](@ref)
            return compareCertificates(localCert, latestCloudCert);

        } catch (Exception e) {
            System.err.println("解析本地证书文件失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 查找域名对应的证书文件
     */
    private File findDomainCertificateFile(File sslDir, String doMain) {
        File[] files = sslDir.listFiles((dir, name) ->
                name.toLowerCase().startsWith(doMain.toLowerCase()) &&
                        name.toLowerCase().endsWith(".crt"));

        return (files != null && files.length > 0) ? files[0] : null;
    }

    /**
     * 比较本地证书与云上证书是否一致
     */
    private boolean compareCertificates(X509Certificate localCert, Certificates cloudCert) {
        try {
            // 比较序列号（最可靠的比较方式）
            String localSerial = localCert.getSerialNumber().toString(16);
            System.out.println("本地证书序列号: " + localSerial);

            // 比较有效期
            Date localNotAfter = localCert.getNotAfter();
            Date cloudNotAfter = DateUtil.parse(cloudCert.getCertEndTime(), "yyyy-MM-dd HH:mm:ss");

            boolean serialMatch = true; // 需要根据实际情况获取云证书序列号
            boolean expiryMatch = localNotAfter.equals(cloudNotAfter);

            // 比较颁发者信息
            String localIssuer = localCert.getIssuerDN().getName();
            System.out.println("本地证书颁发者: " + localIssuer);

            // 比较主题信息
            String localSubject = localCert.getSubjectDN().getName();
            System.out.println("本地证书主题: " + localSubject);

            boolean isConsistent = expiryMatch; // 可以根据需要调整比较逻辑

            System.out.println("证书一致性检查结果: " + (isConsistent ? "一致" : "不一致"));
            return isConsistent;

        } catch (Exception e) {
            System.err.println("比较证书时发生错误: " + e.getMessage());
            return false;
        }
    }

}
